package top.kaoshanji.p3ch26b;

import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * author kaoshanji
 * ^_^
 * create time 2025/3/4 18:25
 */
public class BasicCompletableFutureDemo {

    // 异步执行服务
    private static ExecutorService executor = Executors.newFixedThreadPool(10);

    private static Random rnd = new Random();

    // 模拟延时
    static int delayRandom(int min, int max) {
        int milli = max > min ? rnd.nextInt(max - min) : 0;
        try {
            Thread.sleep(min + milli);
        } catch (InterruptedException e) {
            /// ///
        }
        return milli;
    }

    // 代码清单-p3ch26b-660页a：使用 Supplier 表示异步任务
    static Supplier<Integer> externalTask = () -> {
        return delayRandom(20, 2000);
    };

    // 代码清单-p3ch26b-660页b：使用 CompletableFuture 调用外部服务
    public static Future<Integer> callExternalService() {
        // 使用 executor 执行 Supplier 表示的任务，返回一个 CompletableFuture，调用后，任务被异步执行，这个方法立即返回
        return CompletableFuture.supplyAsync(externalTask, executor);
    }

    // 代码清单-p3ch26b-662页a：使用 CompletableFuture 也可以直接创建线程，并返回结果
    public static Future<Integer> callExternalService2() {
        CompletableFuture<Integer> future = new CompletableFuture<>();
        new Thread() {
            @Override
            public void run() {
                try {
                    future.complete(externalTask.get());
                } catch (Exception e) {
                    future.completeExceptionally(e);
                }
            }
        }.start();
        return future;
    }

    // 代码清单-p3ch26b-662页b：whenComplete方法示例
    public static void whenCompleteDemo() {
        // 参数 action 表示回调函数，不管前一个阶段是正常结束还是异常结束，它都会被调用
        // result 表示前一个阶段的结果，ex 表示异常，只可能有一个不为 null
        CompletableFuture.supplyAsync(externalTask).whenComplete((result, ex) -> {
            if (result != null) {
                System.out.println(result);
            }

            if (ex != null) {
                ex.printStackTrace();
            }
        }).join();
    }

    // 代码清单-p3ch26b-663页a：handle方法示例
    public static void handleDemo() {
        // 接收两个参数，一个是正常结果。另一个是异常
        // 结果会被 BitFunction 的返回值替代，即使原来有异常，也会被覆盖
        String ret = CompletableFuture.supplyAsync(() -> {
            throw new RuntimeException("test");
        }).handle((result, ex) -> {
            return "hello";
        }).join();

        System.out.println(ret);
    }

    // 代码清单-p3ch26b-664页a：在一个阶段正常完成后，执行下一个任务
    public static void taskStreamThenRun() {
        Runnable taskA = () -> System.out.println("task A");
        Runnable taskB = () -> System.out.println("task B");
        Runnable taskC = () -> System.out.println("task C");

        CompletableFuture.runAsync(taskA)
                .thenRun(taskB)
                .thenRun(taskC)
                .join();
    }

    // 代码清单-p3ch26b-665页a：如果下一个任务需要前一个阶段的结果作为参数
    public static void taskStreamThenApply() {
        Supplier<String> taskA = () -> "hello";
        Function<String, String> taskB = (t) -> t.toUpperCase();
        Consumer<String> taskC = (t) -> System.out.println("consume: " + t);

        CompletableFuture.supplyAsync(taskA)
                .thenApply(taskB)
                .thenAccept(taskC)
                .join();
    }

    // 代码清单-p3ch26b-665页b：与thenApply类似，还有一个方法thenCompose
    public static void taskStreamThenCompose() {
        Supplier<String> taskA = () -> "hello";
        Function<String, CompletableFuture<String>> taskB = (t) -> CompletableFuture.supplyAsync(() -> t.toUpperCase());
        Consumer<String> taskC = (t) -> System.out.println("consume: " + t);

        CompletableFuture.supplyAsync(taskA)
                .thenCompose(taskB)
                .thenAccept(taskC)
                .join();
    }

    // 代码清单-p3ch26b-666页a：构建依赖两个阶段的任务流
    public static void taskStreamThenCombine() {
        Supplier<String> taskA = () -> "taskA";
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> "taskB");
        BiFunction<String, String, String> taskC = (a, b) -> a + "," + b;

        String ret = CompletableFuture.supplyAsync(taskA).thenCombineAsync(taskB, taskC).join();

        System.out.println(ret);
    }

    // 代码清单-p3ch26b-667页a：构建依赖多个阶段的任务流
    public static void taskStreamAllOf() {
        CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() -> {
            delayRandom(100, 1000);
            return "helloA";
        }, executor);

        CompletableFuture<Void> taskB = CompletableFuture.runAsync(() -> {
            delayRandom(2000, 3000);
        }, executor);

        CompletableFuture<Void> taskC = CompletableFuture.runAsync(() -> {
            delayRandom(30, 100);
            throw new RuntimeException("task C exception");
        }, executor);

        CompletableFuture.allOf(taskA, taskB, taskC).whenComplete((result, ex) -> {
           if (ex != null) {
               System.out.println(ex.getMessage());
           }

           if (!taskA.isCompletedExceptionally()) {
               System.out.println("task A " + taskA.join());
           }
        });

    }





}
